package com.frank.oj.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.frank.model.dto.TestJudgeReq;
import com.frank.model.dto.TestJudgeRes;
import com.frank.model.dto.ToJudgeDTO;
import com.frank.model.entity.judge.Judge;
import com.frank.model.entity.problem.Problem;
import com.frank.oj.common.Constants;
import com.frank.oj.core.judge.JudgeContext;
import com.frank.oj.core.remoteJudge.RemoteJudgeContext;
import com.frank.oj.dao.JudgeEntityService;
import com.frank.oj.dao.ProblemEntityService;
import com.frank.oj.exception.SystemError;
import com.frank.oj.service.JudgeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Objects;

/**
 * @author frank
 * @Date 2024/4/26
 */
@Service
public class JudgeServiceImpl implements JudgeService {
    @Value("${hcoj-judge-server.name}")
    private String name;

    @Resource
    private JudgeEntityService judgeEntityService;

    @Resource
    private ProblemEntityService problemEntityService;

    @Resource
    private JudgeContext judgeContext;

    @Resource
    private RemoteJudgeContext remoteJudgeContext;

    @Override
    public TestJudgeRes testJudge(TestJudgeReq testJudgeReq) {
        return judgeContext.testJudge(testJudgeReq);
    }

    @Override
    public void judge(Judge judge) {

        // 更新判题状态——编译
        LambdaUpdateWrapper<Judge> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Judge::getStatus, Constants.Judge.STATUS_COMPILING.getStatus())
                .set(Judge::getJudger,name)
                .eq(Judge::getSubmitId,judge.getSubmitId())
                .ne(Judge::getStatus,Constants.Judge.STATUS_CANCELLED.getStatus());
        boolean updated = judgeEntityService.update(updateWrapper);

        if (!updated){ // 更新失败:可能判题取消或者提交被删除
            judgeContext.updateOtherTable(judge.getSubmitId(),
                    Constants.Judge.STATUS_CANCELLED.getStatus(),
                    judge.getCid(),
                    judge.getUid(),
                    judge.getPid(),
                    judge.getGid(),
                    null,
                    null);

            return;
        }

    //    判题
        QueryWrapper<Problem> queryWrapper = new QueryWrapper<>();
            queryWrapper.select("id",
                        "type",
                        "io_score",
                        "difficulty",
                        "judge_mode",
                        "judge_case_mode",
                        "time_limit",
                        "memory_limit",
                        "stack_limit",
                        "user_extra_file",
                        "judge_extra_file",
                        "case_version",
                        "spj_code",
                        "spj_language",
                        "problem_id",
                        "is_remove_end_blank",
                        "is_file_io",
                        "io_read_file_name",
                        "io_write_file_name")
                .eq("id", judge.getPid());
        Problem problem = problemEntityService.getOne(queryWrapper);
        Judge finalJudgeRes = judgeContext.judge(problem, judge); //判题入口

        judgeEntityService.updateById(finalJudgeRes);

        if (!Objects.equals(finalJudgeRes.getStatus(), Constants.Judge.STATUS_SUBMITTED_FAILED.getStatus())) {
            // 更新其它表
            judgeContext.updateOtherTable(finalJudgeRes.getSubmitId(),
                    finalJudgeRes.getStatus(),
                    judge.getCid(),
                    judge.getUid(),
                    judge.getPid(),
                    judge.getGid(),
                    finalJudgeRes.getScore(),
                    finalJudgeRes.getTime());
        }
    }

    @Override
    public void compileSpj(String code, Long pid, String language, HashMap<String, String> extraFiles) throws SystemError {
        judgeContext.compileSpj(code, pid, language, extraFiles);
    }

    @Override
    public void compileInteractive(String code, Long pid, String language, HashMap<String, String> extraFiles) throws SystemError {
        judgeContext.compileInteractive(code, pid, language, extraFiles);
    }

    @Override
    public void remoteJudge(ToJudgeDTO toJudgeDTO) {
        Judge judge = toJudgeDTO.getJudge();
        LambdaUpdateWrapper<Judge> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Judge::getStatus, Constants.Judge.STATUS_PENDING.getStatus())
                .set(Judge::getJudger,name)
                .eq(Judge::getSubmitId,judge.getSubmitId())
                .ne(Judge::getStatus, Constants.Judge.STATUS_CANCELLED.getStatus());
        boolean updated = judgeEntityService.update(updateWrapper);

        if (!updated){
            judgeContext.updateOtherTable(judge.getSubmitId(),
                    Constants.Judge.STATUS_CANCELLED.getStatus(),
                    judge.getCid(),
                    judge.getUid(),
                    judge.getPid(),
                    judge.getGid(),
                    null,
                    null);
            return;
        }
        remoteJudgeContext.judge(toJudgeDTO);
    }
}
